﻿using System;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;

namespace TaskBoardProject
{
   public enum TaskPriority 
    {
        High,
        Medium,
        Low
    }
    /// <summary>
    /// Class that describes Task (fields and methods) to be done by employee
    /// </summary>
   public class Task : IComparable<Task>, IXmlSerializable //: ICloneable, IComparable, IDisposable they are commented because I cant compile code (c) Pavlo
    {
        /// <summary>
        /// String that contains name of the project
        /// </summary>
        string projectName;
        /// <summary>
        /// String that contains name of the task
        /// </summary>
        string taskName;
        /// <summary>
        /// String with task's description
        /// </summary>
        string taskDescription;
        /// <summary>
        /// Enum that defines the task's priority
        /// </summary>
        TaskPriority taskPriority;
        /// <summary>
        /// Describes the start of this task
        /// </summary>
        DateTime timeFrom;
        /// <summary>
        /// Defines deadline for this task to  be done
        /// </summary>
        DateTime timeTo;
        /// <summary>
        /// Defines the responsible employee for this task to be done
        /// </summary>
        Person assignedEmploye;

        public Task()
        {
            projectName = "Default Project";
            taskName = "Undefined task";
            taskDescription = "None";
            taskPriority = TaskPriority.Medium;
            timeFrom = DateTime.Now;
            timeTo = timeFrom.AddDays(2);
            assignedEmploye = new Person();
        }
        public Task(string projectName, string taskName, string taskDescription, TaskPriority taskPriority,
            DateTime timeFrom, DateTime timeTo, string assignedEmploye)
        {
            if (projectName != null)
                this.projectName = projectName;
            else this.projectName = "Default Project";
            if (taskName != null)
                this.taskName = taskName;
            else this.taskName = "Undefined task";
            if (taskDescription != null)
                this.taskDescription = taskDescription;
            else this.taskDescription = "None";
            this.taskPriority = taskPriority;
            if (timeFrom <= timeTo)
            {
                this.timeFrom = timeFrom;
                this.timeTo = timeTo;
            }
            else 
            {
                this.timeFrom = timeTo;
                this.timeTo = timeFrom;
            }
            this.assignedEmploye = new Person(assignedEmploye);
        }

        /// <summary>
        /// Shows information about Task
        /// </summary>
        public void ShowInfo()
        {
            Console.WriteLine(projectName + " " + taskName + " " + assignedEmploye.ToString());
        }

        #region Volodymyr Komaniak - implementation of ICloneable interface using method Clone()
        /// <summary>
        /// Clone all fields of class "Task"
        /// </summary>
        /// <returns>object type of class "Task"</returns>
        public object Clone()
        {
            return new Task(this.projectName,
            this.taskName,
            this.taskDescription,
            this.taskPriority,
            this.timeFrom,
            this.timeTo,
            this.assignedEmploye.ToString());

            //or we can write just: return this;
        }
        #endregion

        
        public override string ToString()
        {
            string taskState =
                String.Format ( "[Project Name: {0}\nTask Name: {1}\nPriority: {2}\nTime: {3} - {4}\nEmployer: {5}\nDescription: {6}]\n",
                projectName, taskName, taskPriority, timeFrom, timeTo, assignedEmploye.ToString(), taskDescription );
            return taskState;
        }

        //only for this ToString (includes all fields)
        public override bool Equals(object obj)
        {
            if ((obj != null) && (obj is Task))
            {
                return obj.ToString() == this.ToString();
            }
            return false;
        }

        // if ToString doesn't include all fields you need override this method as:
        //public override bool Equals(object obj)
        //{
        //    if (obj != null && obj is Task)
        //    {
        //        Task compareTask = (Task)obj;
        //        if (this.taskName == compareTask.taskName &&
        //            this.projectName == compareTask.projectName &&
        //            this.taskPriority == compareTask.taskPriority &&
        //            this.timeFrom == compareTask.timeFrom &&
        //            this.timeTo == compareTask.timeTo &&
        //            this.assignedEmploye.Equals(compareTask.assignedEmploye))
        //        {
        //            return true;
        //        }
        //    }
        //    return false;
        //}


        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        /// <summary>
        /// Compare two tasks 
        /// </summary>
        /// <param name="other">Second task</param>
        /// <returns>result of comparing</returns>
        public int CompareTo(Task other)
        {
            if (other == null)
                return 1;
            else
            {
                // Compare by name
                int nameCompare = taskName.CompareTo(other.taskName);
                if (nameCompare != 0)
                {
                    return nameCompare;
                }
                else
                {
                    // Compare by priority
                    int priorityCompare = taskPriority.CompareTo(other.taskPriority);
                    if (priorityCompare != 0)
                    {
                        return priorityCompare;
                    }
                    else
                    {
                        // Compare by time
                        return timeTo.CompareTo(other.timeTo);
                    }
                }
            }
        }

        /// <summary>
        /// Override operation > for tasks
        /// </summary>
        /// <param name="task1">first task</param>
        /// <param name="task2">second task</param>
        /// <returns>result of comparing</returns>
        public static bool operator > (Task task1, Task task2)
        {
            if (task1 == null && task2 == null)
                return false;
            else if (task1 == null)
                return false;
            else if (task2 == null)
                return true;
            else
                return task1.taskPriority > task2.taskPriority;
        }

        /// <summary>
        /// Override operation < for tasks
        /// </summary>
        /// <param name="task1">first task</param>
        /// <param name="task2">second task</param>
        /// <returns>result of comparing</returns>
        public static bool operator < (Task task1, Task task2)
        {
            if (task1 == null && task2 == null)
                return false;
            else if (task1 == null)
                return false;
            else if (task2 == null)
                return true;
            else
                return task1.taskPriority < task2.taskPriority;
        }

        /// <summary>
        /// Overrided operator == for Task
        /// </summary>
        /// <param name="firstTask">first task</param>
        /// <param name="secondTask">second task</param>
        /// <returns>Return true if first task equals to second task; false if  first task doesn't equals to second</returns>
        /*
        public static bool operator == (Task firstTask, Task secondTask)
        {
                return firstTask.Equals(secondTask);
        }
        */

        /// <summary>
        /// Overrided operator != for Task
        /// </summary>
        /// <param name="firstTask">first task</param>
        /// <param name="secondTask">second task</param>
        /// <returns>Return false if first task equals to second task; true if  first task doesn't equals to second</returns>
        /*
        public static bool operator != (Task firstTask, Task secondTask)
        {
                return !firstTask.Equals(secondTask);
        }
        */

        // Added property for accessibility to class field in Comparer class (c) Vitalik Sh.

        /// <summary>
        /// Gets name of project
        /// </summary>
        public string ProjectName
        {
            get
            {
                return projectName;
            }
            set { projectName = value; } // for cloning example;
        }

        /// <summary>
        /// Gets name of task
        /// </summary>
        public string TaskName
        {
            get
            {
                return taskName;
            }
        }

        /// <summary>
        /// Gets time of beginning task
        /// </summary>
        public DateTime TimeFrom
        {
            get
            {
                return timeFrom;
            }
        }

        /// <summary>
        /// Gets time of ending task
        /// </summary>
        public DateTime TimeTo
        {
            get
            {
                return timeTo;
            }
        }

        /// <summary>
        /// Gets task priority
        /// </summary>
        public TaskPriority TaskPriority
        {
            get
            {
                return taskPriority;
            }
        }

        /// <summary>
        /// Gets task description
        /// </summary>
        public string TaskDescription
        {
            get
            {
                return taskDescription;
            }
        }

        /// <summary>
        /// Gets assigned employee
        /// </summary>
        public string AssignedEmploye
        {
            get
            {
                return assignedEmploye.ToString();
            }
        }

        // Xml Serialization Infrastructure (c) Gants

        /// <summary>
        /// Converts an object into its XML representation.
        /// </summary>
        /// <param name="writer">The XmlWriter stream to which the object is serialized</param>
        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString("projectName", projectName);
            writer.WriteElementString("taskName", taskName);
            writer.WriteElementString("taskDescription", taskDescription);
            writer.WriteElementString("taskPriority", taskPriority.ToString());
            writer.WriteElementString("timeFrom", timeFrom.ToString());
            writer.WriteElementString("timeTo", timeTo.ToString());
            writer.WriteElementString("assignedEmploye", assignedEmploye.ToString());

            /*writer.WriteAttributeString("projectName", projectName);
            writer.WriteAttributeString("taskName", taskName);
            writer.WriteAttributeString("taskDescription", taskDescription);
            writer.WriteAttributeString("taskPriority", taskPriority.ToString());
            writer.WriteAttributeString("timeFrom", timeFrom.ToString());
            writer.WriteAttributeString("timeTo", timeTo.ToString());
            writer.WriteAttributeString("assignedEmploye", assignedEmploye.ToString());
            /*writer.WriteAttributeString("projectName", projectName);
            writer.WriteAttributeString("taskName", taskName);
            writer.WriteAttributeString("taskDescription", taskDescription);
            writer.WriteAttributeString("taskPriority", taskPriority.ToString());
            writer.WriteAttributeString("timeFrom", timeFrom.ToString());
            writer.WriteAttributeString("timeTo", timeTo.ToString());
            writer.WriteAttributeString("assignedEmploye", assignedEmploye.ToString());*/
        }

        /// <summary>
        /// Generates an object from its XML representation
        /// </summary>
        /// <param name="reader">The XmlReader stream from which the object is deserialized</param>
        public void ReadXml(XmlReader reader)
        {
            reader.MoveToContent();
            reader.Read();
            reader.MoveToContent();

            projectName = reader.ReadInnerXml();
            reader.MoveToContent();

            taskName = reader.ReadInnerXml();
            reader.MoveToContent();

            taskDescription = reader.ReadInnerXml();
            reader.MoveToContent();

            taskPriority = (TaskPriority)Enum.Parse(typeof(TaskPriority), reader.ReadInnerXml());

            timeFrom = DateTime.Parse(reader.ReadInnerXml());
            reader.MoveToContent();

            timeTo = DateTime.Parse(reader.ReadInnerXml());
            reader.MoveToContent();

            assignedEmploye = new Person(reader.ReadInnerXml());
            //Console.WriteLine(reader.ReadInnerXml());

            reader.Read();

            /*projectName = reader["projectName"]; //Console.WriteLine(projectName);
            taskName = reader["taskName"];
            taskDescription = reader["taskDescription"];
            taskPriority = (TaskPriority)Enum.Parse(typeof(TaskPriority), reader["taskPriority"]);
            timeFrom = DateTime.Parse(reader["timeFrom"]);
            timeTo = DateTime.Parse(reader["timeTo"]);
            assignedEmploye = new Person(reader["assignedEmploye"]);
            reader.Read();*/
        }

        /// <summary>
        /// This method is reserved and should not be used
        /// </summary>
        /// <returns></returns>
        public XmlSchema GetSchema()
        {
            return (null);
        }
    }
}
